/**
 * 1: saveGetState = applyMiddleWare([reduxLog, reduxThunk])
 * 2: reducer函数用来修改state的值
  function reducer(state=initState, action?: Action) {
    if (action?.type === 'add') {
      return {
        ...state,
        age: state.age + action.payload
      }
    }
    if (action?.type === 'minus') {
      return {
        ...state,
        age: state.age - action.payload
      }
    }
    return state
  }
 */
export const createStore = <S, A>(reducer: Function, saveGetState?: Function) => {
  let state: S = reducer()
  let fns: Function[] = []
  const getState = () => state

  const subscrible = (refresh: Function) => {
    fns.push(refresh)
    return () => {
      const index = fns.indexOf(refresh);
      fns.splice(index, 1);
    }
  }

  let dispatch = (action: A) => {
    state = reducer(state, action)
    fns.forEach(refresh => refresh())
  }
  type NewDispatch = typeof dispatch | undefined
  let newDispatch: NewDispatch = undefined

  if (saveGetState) {
    const enhanceDispatch = saveGetState(getState) // 存入getState函数给中间件用
    newDispatch = enhanceDispatch(dispatch) // 中间件加强dispatch函数
  }

  return {
    getState,
    subscrible,
    dispatch: newDispatch || dispatch
  }
}
/**
 * 合成函数
 @param middlewares = [
      (next) => (arg) => {
          console.log(arg, "start-1");
          next(arg);
          console.log(arg, "end-1");
      },
      (next) => (arg) => {
          console.log(arg, "start-2");
          next(arg);
          console.log(arg, "end-2");
      },
      (next) => (arg) => {
          console.log(arg, "start-3");
          next(arg);
          console.log(arg, "end-3");
      }
  ];
  @param action 是next的参数
 */
const run = (midwares: Function[]) => (action: any) => {
  /**
   * 
   * @param i 选择midwares第i个函数执行
   * @param arg next的参数
   */
  const chooseFnRun = (i: number, arg: any) => {
    const fn = midwares[i]
    if (!fn) return
    const next = (arg: any) => chooseFnRun(i + 1, arg)
    fn(next)(arg)
  }
  chooseFnRun(0, action)
}
/**
 * 中间件
 */
export const applyMiddleWare = (...middlewares: Function[]) => (getState: Function) => (dispatch: Function) => {
  middlewares = middlewares.map(
    fn => fn({getState, dispatch})
  )
  middlewares = [
    ...middlewares,
    (next: Function) => (action: any) => {
      dispatch(action)
      next()
    }
  ]
  /**
   * 中间件加强后的dispatch
   */
  const newDispatch = (action: any) => {
    run(middlewares)(action)
  }

  return newDispatch
}

